import numpy as np
from scipy.stats import chi2
from math import log2, exp, floor, fabs
# 自定义的遗传算法
import ga.genetic_algorithm as myga


def GA(m, theta, eta, D, maxT, maxN, parent, parentNum, nodeValueNum, subSampleNum, sampleNum, delta):
    """
    略
    """
    # 样本数量
    M = D.shape[0]
    # 贝叶斯网络结点数量
    n = D.shape[1]
    # 种群数量
    Nind = 200
    # 染色体长度
    chromosomeLen = delta
    # 种群迭代次数
    iterNum = 10
    # 上界
    lb = 0
    # 下界
    ub = M-1
    # 生成初始种群
    pop = myga.generate(Nind, chromosomeLen, lb, ub)
    # 分配内存，必须是浮点型
    chiScore = np.zeros((Nind, 1))
    dScore = np.zeros((Nind, 1))
    zero_chiScore = np.zeros((Nind, 1))
    node_chiScore = np.zeros((Nind, 1))
    # 进行种群迭代
    for ii in range(iterNum):
        # 计算种群中每个个体（染色体）加入到子数据集后的评分
        for jj in range(pop.shape[0]):
            # 调整index的形状
            index = pop[jj, :].reshape((1, chromosomeLen))
            sub = D[tuple(index[0, :]), :]
            # 计算数据集sub的idxJ
            idxJ = encodeParent(sub, parent, parentNum, nodeValueNum)
            # 数据集sub的分布参数m
            mAsterisk = distCal(sub, idxJ, maxT, maxN)
            # 将数据集sub加入子数据集后的评分
            (chiScore[jj, 0], dScore[jj, 0], zero_chiScore[jj, 0], node_chiScore[jj, 0])\
                = scoreCal(m, mAsterisk, theta,
                            eta, parent, nodeValueNum, subSampleNum, sampleNum, delta)
        # 评分，必须是array类型，且shape是Nind行1列的（列向量）
        # score越小越好
        score = chiScore * exp(10) - dScore
        # 当代最优个体（染色体）
        best_ind = pop[findBest(score), :].reshape(1, chromosomeLen)
        # 生成适应度（数量为score的行数），score越小，适应度越大。
        FitnV = myga.rank(score)
        # 第三个参数若大于1，则为选择的数量，非整数向上取整
        # 返回值pSet为被选择个体在pop中的索引号，行向量（1行n列的array）
        pSet = myga.select(FitnV, Nind-1)
        # 待重组的染色体矩阵
        pop = pop[pSet, :]
        # 重组概率为0.9
        pop = myga.uniform_crossover(pop, 0.9)
        # 采用的编码方式为RI，译码矩阵为FieldDR
        # 变异概率为1/chromosomeLen
        # pop = ea.mutuni('RI', pop, FieldDR, 1/chromosomeLen)
        pop = myga.mutate(pop, lb, ub, 1/chromosomeLen)
        # 与最优个体合并
        pop = np.concatenate((pop, best_ind), axis=0)
    # 计算分别将pop中每个个体（染色体）加入抽样出来的子样本后的子样本的评分
    for jj in range(pop.shape[0]):
        index = pop[jj, :].reshape((1, chromosomeLen))
        # 计算数据集D[tuple(index[0, :]), :]的idxJ
        idxJ = encodeParent(D[tuple(index[0, :]), :], parent, parentNum, nodeValueNum)
        mAsterisk = distCal(D[tuple(index[0, :]), :], idxJ, maxT, maxN)
        (chiScore[jj, 0], dScore[jj, 0], zero_chiScore[jj, 0], node_chiScore[jj, 0]) \
            = scoreCal(m, mAsterisk, theta,
                       eta, parent, nodeValueNum, subSampleNum, sampleNum, delta)
    # 评分越低越好
    score = chiScore * exp(10) - dScore
    best = findBest(score)
    # 返回最优的一个个体以及将其加入子数据集后的评分chiScore
    return pop[best, :].reshape(1, chromosomeLen), \
           int(chiScore[best, 0]), int(dScore[best, 0]), \
           int(zero_chiScore[best, 0]), int(node_chiScore[best, 0])


def preProcess(sample, idxJ, parent, nodeValueNum):
    """
    函数功能：
    （1）将贝叶斯网络中每个结点的父结点所有不同取值编码，方便快速访问
    （2）计算数据集sample的参数theta和eta
    输入参数：
    （1）sample
        m行n列的矩阵，其中m表示样本数量，n表示贝叶斯网络结点的数量，numpy.array类型（int）。
    sample[i, j]表示第i+1个样本中第j+1个结点的取值。
    （2）parent
        设贝叶斯网络结点数量为n，则parent为n行n列的矩阵，类型为numpy.array类型（int）。
    若parent[i, j]不等于0，则表示第i+1个结点是父结点是parent[i, j]；否则，不是。
    （3）parentNum
        设贝叶斯网络结点数量为n，则parentNum为1行n列的矩阵，类型为numpy.array类型（int）。
    parentNum[0, i]表示第i+1个结点的父结点数量。
    （4）nodeValueNum
        设贝叶斯网络结点数量为n，则parentNum为1行n列的矩阵，类型为numpy.array类型（int）。
    nodeValueNum[0, i]表示第i+1个结点的取值数量。
    返回值：
    （1）theta
        theta[i, j, k]表示在数据集sample中，在第i+1个结点的父结点取第j+1种取值的条件下
    第i+1个结点取第k+1种取值的概率。numpy.array类型（浮点型）
    （2）eta
        eta[i, j, k]表示在数据集sample中，第i+1个结点的父结点取第j+1种取值且
    第i+1个结点取第k+1种取值的概率。numpy.array类型（浮点型）
    """
    # 样本数量
    m = sample.shape[0]
    # 结点（变量，属性）个数
    n = sample.shape[1]
    # totalC[0, i]表示第i+1个结点的所有父结点不同取值的组合数量（不包括不存在父节点的情况）
    totalC = getParentCombination(parent, nodeValueNum)
    # 最大的父结点排列组合情况
    maxT = np.max(totalC)
    # 最大的结点不同取值的情况
    maxN = np.max(nodeValueNum)
    # 预分配内存，浮点型
    theta = np.zeros((n, maxT, maxN))
    # 累加theta
    for h in range(m):
        for i in range(n):
            # 若第i+1个结点在第h个样本中的取值为-1，则表示该结点无父结点
            if idxJ[h, i] != -1:
                theta[i, idxJ[h, i], sample[h, i]] += 1
            # 没有父结点，则为第i+1个结点取值为sample[h, i]的数量
            else:
                theta[i, 0, sample[h, i]] += 1
    # 预分配，浮点型
    eta = np.zeros((n, maxT, maxN))
    for i in range(n):
        for j in range(maxT):
            sum = 0
            for k in range(maxN):
                sum += theta[i, j, k]
            for k in range(maxN):
                eta[i, j, k] = theta[i, j, k] / m
                if sum != 0:
                    theta[i, j, k] = theta[i, j, k] / sum
    return theta, eta


def scoreCal(m, mAsterisk, theta, eta, parent, nodeValueNum, subSampleNum, sampleNum, delta):
    """
    函数功能：将遗传算法得到的子样本添加到最终结果后的评分
    """
    # 贝叶斯网络结点数量
    n = m.shape[0]
    # 初始化，chiScore是整型，dScore是浮点型
    chiScore = 0
    dScore = 0.0
    zero_chiScore = 0
    node_chiScore = 0
    # vis[0, i]等于1表示第i+1个结点未通过卡方检验，用于求解dScore
    vis = np.zeros((1, n), dtype=int)
    # 父结点取值情况行向量
    totalC = getParentCombination(parent, nodeValueNum)
    # 计算mCaret，其为将遗传算法得到的一个个体（样本量为delta的数据集）加入到子数据集后的分布参数m
    mCaret = m + mAsterisk
    # 未通过卡方检验的结点编号
    node = np.zeros((1, n), dtype=int)
    # 存储node中结点编号的数量
    nodeSize = 0
    # 卡方检验的分位数
    alpha = 0.05
    # 每次样本增量取为delta
    newSize = subSampleNum + delta
    zero_theta = 0
    # 处理totalC
    # 若totalC[0, i]为0，表示第i+1个结点没有父结点，因此为了处理方便，就加上1
    for i in range(n):
        if totalC[0, i] == 0:
            totalC[0, i] += 1
    for i in range(n):
        p2, chiSquare2 = merge(eta[i], mCaret[i],
            totalC[0, i], nodeValueNum[0, i], newSize, 5)
        for j in range(totalC[0, i]):
            sum = 0.0
            sum_theta = 0.0
            chiSquare1 = 0.0
            # 第一个卡方检验的自由度
            p1 = nodeValueNum[0, i] - 1
            for k in range(nodeValueNum[0, i]):
                sum = sum + mCaret[i, j, k]
                sum_theta += theta[i, j, k]
            if sum_theta == 0:
                zero_theta += 1
            # 若sum_theta为0，则sum必为0，必须排除这种情况
            if sum_theta != 0 and sum == 0:
                chiScore += 1
                zero_chiScore += 1
                if vis[0, i] == 0:
                    vis[0, i] = 1
                    node[0, nodeSize] = i
                    nodeSize += 1
            # 每个变量的取值数量超过2时才进行合并
            if nodeValueNum[0, i] > 2:
                p1, chiSquare1 = merge(theta[i, j].reshape(1, theta.shape[2]),
                    mCaret[i, j].reshape(1, mCaret.shape[2]), 1, nodeValueNum[0, i], sum, 5)
            else:
                for k in range(nodeValueNum[0, i]):
                    if theta[i, j, k] != 0:
                        if sum != 0:
                            chiSquare1 += (mCaret[i, j, k] - theta[i, j, k] * sum) ** 2 / (theta[i, j, k] * sum)
                    # theta[i, j, k]为0，两个卡方分布的自由度都减去1
                    else:
                        p1 -= 1
                        # p2 -= 1
                # print(p1, chiSquare1)
            # 若自由度不是正整数，就不需要卡方检验
            if p1 <= 0:
                continue
            if chiSquare1 >= chi2.ppf(1 - alpha, p1):
                chiScore += 1
                if vis[0, i] == 0:
                    vis[0, i] = 1
                    node[0, nodeSize] = i
                    nodeSize += 1
        # 若自由度不是正整数，就不需要卡方检验
        if p2 <= 0:
            continue
        if chiSquare2 >= chi2.ppf(1 - alpha, p2):
            node_chiScore += 1
            chiScore += 1
            if vis[0, i] == 0:
                vis[0, i] = 1
                node[0, nodeSize] = i
                nodeSize += 1
    # 允许有一定数量的0
    if zero_chiScore <= 1 * zero_theta:
        # print("允许有一定数量的0")
        chiScore -= zero_chiScore
        zero_chiScore = 0
    # 计算dScore
    for ii in range(nodeSize):
        i = node[0, ii]
        for j in range(totalC[0, i]):
            sumM = 0
            sum = 0
            for k in range(nodeValueNum[0, i]):
                sumM += m[i, j, k]
                sum += mCaret[i, j, k]
            for k in range(nodeValueNum[0, i]):
                if mCaret[i, j, k] != 0 and sum != 0 and m[i, j, k] != 0 and sumM != 0:
                    dScore += theta[i, j, k] * sampleNum * log2((mCaret[i, j, k] * sumM) / (m[i, j, k] * sum))
                else:
                    dScore += theta[i, j, k] * sampleNum * log2(2/sampleNum)
    # 返回
    return chiScore, dScore, zero_chiScore, node_chiScore


def distCal(deltaD, idxJ, maxT, maxN):
    """
    输入参数：
        （1）deltaD
            m行n列的矩阵，其中m表示样本数量，n表示贝叶斯网络结点的数量，numpy.array类型（int）。
        deltaD[i, j]表示第i+1个样本中第j+1个结点的取值。
        （2）idxJ
            来自函数preProcess的返回值
        （3）index
            设贝叶斯网络结点数量为n，则index为1行n列的矩阵，类型为numpy.array类型（int）。
        index[0, i]表示deltaD中第i+1个样本在原来的样本中的样本编号。
        （4）maxT
            函数getParentCombination的返回值totalC中的最大值
        （5）maxN
            变量nodeValueNum中的最大值
    返回值：
        （1）mAsterisk
            数据集delta的分布参数m
            n-by-maxT-by-maxN的矩阵，类型为numpy.array类型（int）。mAsterisk[i, j, k]
        表示第i+1个结点取第k+1种取值，且第i+1个结点的父结点取第j+1种取值的数量（在样本deltaD中）
    """
    # deltaD中的样本数量
    m = deltaD.shape[0]
    # 结点数量
    n = deltaD.shape[1]
    # 预分配
    mAsterisk = np.zeros((n, maxT, maxN), dtype=int)
    # 计算mAsterisk
    # ii表示delta中第ii+1个样本点
    for ii in range(m):
        # i表示贝叶斯网络中第i+1个结点
        for i in range(n):
            # 若存在父结点
            if idxJ[ii, i] != -1:
                mAsterisk[i, idxJ[ii, i], deltaD[ii, i]] += 1
            # 不存在父结点
            else:
                mAsterisk[i, 0, deltaD[ii, i]] += 1
    # 返回mAsterisk
    return mAsterisk


def getParentNum(parent):
    """
    输入参数：
        （1）parent
            设贝叶斯网络结点数量为n，则parent为n行n列的矩阵，类型为numpy.array类型（int）。
        若parent[i, j]不等于0，则表示第j+1个结点是第i+1个结点的父亲结点；否则，不是。
    返回值：
        （2）parentNum
            设贝叶斯网络结点数量为n，则parentNum为1行n列的矩阵，类型为numpy.array类型（int）。
        parentNum[0, i]表示第i+1个结点的父结点数量。
    """
    # 结点数量
    n = parent.shape[0]
    # 预分配空间
    parentNum = np.zeros((1, n), dtype=int)
    # 求父结点数量
    for row in range(n):
        for col in range(n):
            if parent[row, col] != 0:
                parentNum[0, row] += 1
            else:
                break
    # 返回parentNum
    return parentNum


def getParentCombination(parent, nodeValueNum):
    """
    输入参数：
        （1）parent
            设贝叶斯网络结点数量为n，则parent为n行n列的矩阵，类型为numpy.array类型（int）。
        若parent[i, j]不等于0，则表示第parent[i, j]个结点是第i+1个结点的父亲结点；否则，不是。
        （2）nodeValueNum
            设贝叶斯网络结点数量为n，则parentNum为1行n列的矩阵，类型为numpy.array类型（int）。
        nodeValueNum[0, i]表示第i+1个结点的取值数量。
    返回值：
        （1）totalC
            设贝叶斯网络结点数量为n，则totalC为1行n列的矩阵，类型为numpy.array类型（int）。
        totalC[0, i]表示第i+1个结点的所有父结点不同取值的组合数量
    """
    # 贝叶斯网络结点数量
    n = nodeValueNum.shape[1]
    # parentNum[0, i]表示第i+1个结点的父结点数量
    parentNum = getParentNum(parent)
    # totalC[0, i]表示第i+1个结点的所有父结点不同取值的组合数量
    totalC = np.ones((1, n), dtype=int)
    # 计算totalC
    for i in range(n):
        if parentNum[0, i] != 0:
            for hh in range(parentNum[0, i] - 1):
                totalC[0, i] = totalC[0, i] * nodeValueNum[0, parent[i, hh] - 1]
            totalC[0, i] = totalC[0, i] * nodeValueNum[0, parent[i, parentNum[0, i] - 1] - 1]
        else:
            # 父结点数量为0，因此第i+1个结点的父结点不同取值数量为0
            totalC[0, i] = 0
    # 返回totalC
    return totalC


def findBest(score):
    """
    函数作用：
        返回score最小的一个个体在种群pop中的下标（优先选择score低的个体，因为score越低越好）。
    输入参数：
    （1）score
        设种群pop中个体数量为m，则pop为m行1列的矩阵。类型为numpy.array类型（int）。
    返回值：
        score最小的一个个体在种群pop中的下标
    """
    # 种群数量
    popNum = score.shape[0]
    # 将score转换为列表类型
    scoreList = score.reshape(1, popNum).tolist()[0]
    # 绑定下标
    temp = zip(scoreList, range(popNum))
    # 排序，从小到大
    temp = sorted(temp, key=lambda x: x[0])
    # 返回score最小的一个个体在种群pop中的下标
    return temp[0][1]


def encodeParent(sample, parent, parentNum, nodeValueNum):
    """
    函数功能：
    （1）将贝叶斯网络中每个结点的父结点所有不同取值编码，方便快速访问
    输入参数：
    （1）sample
        m行n列的矩阵，其中m表示样本数量，n表示贝叶斯网络结点的数量，numpy.array类型（int）。
    sample[i, j]表示第i+1个样本中第j+1个结点的取值。
    （2）parent
        设贝叶斯网络结点数量为n，则parent为n行n列的矩阵，类型为numpy.array类型（int）。
    若parent[i, j]不等于0，则表示第i+1个结点是父结点是parent[i, j]；否则，不是。
    （3）parentNum
        设贝叶斯网络结点数量为n，则parentNum为1行n列的矩阵，类型为numpy.array类型（int）。
    parentNum[0, i]表示第i+1个结点的父结点数量。
    （4）nodeValueNum
        设贝叶斯网络结点数量为n，则parentNum为1行n列的矩阵，类型为numpy.array类型（int）。
    nodeValueNum[0, i]表示第i+1个结点的取值数量。
    返回值：
    （1）idxJ
        贝叶斯网络中每个结点的父结点所有不同取值的编码。m行n列的矩阵。numpy.array类型（int）。
    idxJ[i, j]表示第j+1个结点的父结点在数据集sample中第i+1个样本点中的取值。
    若idxJ[i, j]为-1，表示第j+1个结点没有父结点，因此特别的给与其值-1。
    """
    # 样本数量
    m = sample.shape[0]
    # 结点（变量，属性）个数
    n = sample.shape[1]
    # 预分配内存
    idxJ = np.zeros((m, n), dtype=int)
    # 将idxJ编码
    # m表示样本数量，该for循环表示遍历所有样本点
    for h in range(m):
        # n表示贝叶斯网络中的结点数量，该for循环表示遍历所有结点
        for i in range(n):
            # 如果第h+1个样本的第i+1个结点存在父结点
            if parentNum[0, i] != 0:
                for hh in range(parentNum[0, i] - 1):
                    idxJ[h, i] = (idxJ[h, i] + sample[h, parent[i, hh] - 1]) * nodeValueNum[0, parent[i, hh + 1] - 1]
                idxJ[h, i] = idxJ[h, i] + sample[h, parent[i, parentNum[0, i] - 1] - 1]
            # 如果第h+1个样本的第j+1个结点不存在父结点
            else:
                # -1表示没有取值，即没有父结点
                idxJ[h, i] = -1
    return idxJ


def validation(theta, m, n, totalC, nodeValueNum):
    count = 0
    delta = 0.0
    for i in range(n):
        if totalC[0, i] == 0:
            totalC[0, i] += 1
    for i in range(n):
        for j in range(totalC[0, i]):
            sum = 0.0
            for k in range(nodeValueNum[0, i]):
                count += 1
                sum += m[i, j, k]
            for k in range(nodeValueNum[0, i]):
                if sum != 0:
                    delta += fabs(m[i, j, k]/sum - theta[i, j, k])
    return delta / float(count)


def merge(eta, m, max_parent_num, max_node_value_num, sample_num, lowest):
    """
    皮尔逊卡方检验中理论频率的合并
    :param eta: 初始数据集D的分布参数eta
    :param m: \delta D‘并入D’后的分布参数m
    :param max_parent_num: 父结点的最大取值数量
    :param max_node_value_num:  最大的结点取值数量
    :param sample_num: \delta D‘并入D’后的数据集数量
    :param lowest: 小于lowest的理论频率都要合并
    :return: 返回卡方检验的自由度和卡方检验值
    """
    eta_to_m = list()
    # 理论频数和实际频数一一对应
    for j in range(max_parent_num):
        for k in range(max_node_value_num):
            eta_to_m.append((eta[j, k] * sample_num, m[j, k]))
    # 根据理论频数从小到大排序
    eta_to_m.sort(key=lambda e: e[0])
    sum_eta = 0.0
    sum_m = 0
    # 卡方检验值
    chi_score = 0.0
    # 分类数量
    freedom = 0
    # 计算卡方值
    for i in range(len(eta_to_m)):
        # 理论频数累加
        sum_eta += eta_to_m[i][0]
        # 实际频数累加
        sum_m += eta_to_m[i][1]
        # 若理论频数大于等于lowest
        if sum_eta >= lowest:
            # 分类数量加1
            freedom += 1
            # 卡方检验值累加
            chi_score += (sum_m - sum_eta)**2 / sum_eta
            # 重置
            sum_eta = 0.0
            sum_m = 0
    # 可能会漏掉最后一个分类，因此需要确定
    if sum_eta != 0.0 or sum_m != 0:
        # 分类数量加1
        freedom += 1
        # 卡方值累加
        chi_score += (sum_m - sum_eta)**2 / sum_eta
    return freedom - 1, chi_score


# def hsa(data_file, node_val_file, parent_file):
#     D = np.loadtxt(data_file, dtype=int)
#     nodeValueNum = np.loadtxt(node_val_file, dtype=int).reshape((1, D.shape[1]))
#     parent = np.loadtxt(parent_file, dtype=int)
#     parentNum = getParentNum(parent)
#     # 每个结点的父结点的取值情况的数量
#     totalC = getParentCombination(parent, nodeValueNum)
#     maxN = np.max(nodeValueNum)
#     maxT = np.max(totalC)
#     # 样本数量
#     M = D.shape[0]
#     # 贝叶斯网络结点数量
#     n = D.shape[1]
#     # 根据数据集D，将父结点编码，用于下述的preProcess
#     idxJ = encodeParent(D, parent, parentNum, nodeValueNum)
#     # 数据集D的分布参数theta和eta
#     theta, eta = preProcess(D, idxJ, parent, nodeValueNum)
#     # 每次抽取的样本数量
#     delta = 10
#     # 计数器
#     cnt = 1
#     # 最大重复次数
#     max_dup = 30
#     # 前一次评分
#     pre_chiScore = -1
#     # 抽取出来的子样本
#     subSample = None
#     # 子样本数量
#     subSampleNum = 0
#     m = np.zeros((n, maxT, maxN), dtype=int)
#     for h in range(floor(M / delta) - 1):
#         print("--------------------------------------------------------------")
#         print("第", h, "次迭代开始")
#         # index表示被选中个体在样本D中的样本编号
#         index, chiScore, dScore, zero_chiScore, node_chiScore \
#             = GA(m, theta, eta, D, maxT, maxN, parent,
#                  parentNum, nodeValueNum, subSampleNum, M, delta)
#         # 经过遗传算法GA选择出来的个体
#         deltaD = D[tuple(index[0, :]), :]
#         # 根据数据集deltaD，将父结点取值编码
#         idxJ = encodeParent(deltaD, parent, parentNum, nodeValueNum)
#         # 计算deltaD的分布参数m
#         mAsterisk = distCal(deltaD, idxJ, maxT, maxN)
#         # 将选择出的数据集deltaD加入数据集subSample后的分布参数m
#         m += mAsterisk
#         # input_theta(m, totalC, nodeValueNum)
#         # 将数据集deltaD加入数据集subSample
#         if subSample is None:
#             subSample = deltaD
#         else:
#             subSample = np.concatenate((subSample, deltaD), axis=0)
#         # 将数据集deltaD从数据集D种剔除
#         D = np.delete(D, tuple(index[0, :]), axis=0)
#         # 数据集subSample样本容量增加
#         subSampleNum += delta
#         print("子样本的chiScore: ", chiScore)
#         print("子样本的dScore: ", dScore)
#         print("子样本的zero_chiScore: ", zero_chiScore)
#         print("子样本的node_chiScore: ", node_chiScore)
#         print("子样本的大小: ", subSampleNum)
#         print("子样本的delta：", validation(theta, m, n, totalC, nodeValueNum))
#         if chiScore == pre_chiScore:
#             cnt += 1
#         else:
#             pre_chiScore = chiScore
#             cnt = 1
#         print("计数器：", cnt)
#         if chiScore == 0 or cnt > max_dup:
#             print("第", h, "次迭代结束")
#             break
#         print("第", h, "次迭代结束")
#     print("离开函数samplingAlgorithm")
#     print("抽样算法执行成功")
#
#     print("--------------------------------------------------------------")
#     print("采样后的子样本的大小：", subSample.shape)
#     print("--------------------------------------------------------------")
#     # 验证subSample的theta和eta，以及distCal的返回值
#     idxJ = encodeParent(subSample, parent, parentNum, nodeValueNum)
#     theta, eta = preProcess(subSample, idxJ, parent, nodeValueNum)
#     mA = distCal(subSample, idxJ, maxT, maxN)
#     input_theta(theta, totalC, nodeValueNum)
#
#     idxJ = encodeParent(D, parent, parentNum, nodeValueNum)
#     theta, _ = preProcess(D, idxJ, parent, nodeValueNum)
#     print("delta: ", validation(theta, mA, D.shape[1], totalC, nodeValueNum))
#
#
# if __name__ == "__main__":
#     # hsa("../data/asia/data_20000.txt", "../data/asia/nodeValueNum.txt", "../data/asia/parent.txt")
#     hsa("../data/sachs/sachs_20000.txt", "../data/sachs/nodeValueNum.txt", "../data/sachs/parent.txt")
